package com.vviton.zyhj.common.utils.alipay;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.NameValuePair;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

/**
 * @Desc 支付宝各接口请求提交类
 * @Author zhangjin
 * @Date 2015年10月30日 下午2:45:26
 */
public class AlipaySubmit {

    /**
     * 支付宝提供给商户的服务接入网关URL(新)
     */
    private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";

    /**
     * @Desc 生成签名结果
     * @Author zhangjin
     * @Date 2015年10月30日 下午2:45:47
     * @param sPara 要签名的数组
     * @return 签名结果字符串
     */
    public static String buildRequestMysign(Map<String, String> sPara) {
        String prestr = AlipayCore.createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        if (AlipayConfig.sign_type.equals("MD5")) {
            mysign = MD5.sign(prestr, AlipayConfig.key, AlipayConfig.input_charset);
        }
        return mysign;
    }

    /**
     * @Desc 生成要请求给支付宝的参数数组
     * @Author zhangjin
     * @Date 2015年10月30日 下午2:46:11
     * @param sParaTemp 请求前的参数数组
     * @return 要请求的参数数组
     */
    private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
        Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp); // 除去数组中的空值和签名参数
        String mysign = buildRequestMysign(sPara); // 生成签名结果
        // 签名结果与签名方式加入请求提交参数组中
        sPara.put("sign", mysign);
        sPara.put("sign_type", AlipayConfig.sign_type);
        return sPara;
    }

    /**
     * @Desc 建立请求，以表单HTML形式构造（默认）
     * @Author zhangjin
     * @Date 2015年10月30日 下午2:46:56
     * @param sParaTemp 请求参数数组
     * @param strMethod 提交方式。两个值可选：post、get
     * @param strButtonName 确认按钮显示文字
     * @return String
     */
    public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName) {
        // 待请求参数数组
        Map<String, String> sPara = buildRequestPara(sParaTemp);
        List<String> keys = new ArrayList<String>(sPara.keySet());

        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + ALIPAY_GATEWAY_NEW + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod + "\">");

        for (int i = 0; i < keys.size(); i++) {
            String name = keys.get(i);
            String value = sPara.get(name);

            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
        }

        // submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
        sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");

        System.out.println(sbHtml.toString());
        return sbHtml.toString();
    }

    /**
     * @Desc 建立请求，以表单HTML形式构造，带文件上传功能
     * @Author zhangjin
     * @Date 2015年10月30日 下午3:23:53
     * @param sParaTemp 请求参数数组
     * @param strMethod 提交方式。两个值可选：post、get
     * @param strButtonName 确认按钮显示文字
     * @param strParaFileName 文件上传的参数名
     * @return 提交表单HTML文本
     */
    public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName, String strParaFileName) {

        Map<String, String> sPara = buildRequestPara(sParaTemp); // 待请求参数数组
        List<String> keys = new ArrayList<String>(sPara.keySet());

        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\"  enctype=\"multipart/form-data\" action=\"" + ALIPAY_GATEWAY_NEW + "_input_charset=" + AlipayConfig.input_charset
                + "\" method=\"" + strMethod + "\">");

        for (int i = 0; i < keys.size(); i++) {
            String name = keys.get(i);
            String value = sPara.get(name);

            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
        }

        sbHtml.append("<input type=\"file\" name=\"" + strParaFileName + "\" />");

        // submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");

        return sbHtml.toString();
    }

    /**
     * @Desc 建立请求，以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
     * @Author zhangjin
     * @Date 2015年10月30日 下午3:24:45
     * @param strParaFileName 文件类型的参数名
     * @param strFilePath 文件路径
     * @param sParaTemp 请求参数数组
     * @return 支付宝处理结果
     * @throws Exception 异常
     */
    public static String buildRequest(String strParaFileName, String strFilePath, Map<String, String> sParaTemp) throws Exception {
        Map<String, String> sPara = buildRequestPara(sParaTemp); // 待请求参数数组

        HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();

        HttpRequest request = new HttpRequest(HttpResultType.BYTES);

        request.setCharset(AlipayConfig.input_charset); // 设置编码集

        request.setParameters(generatNameValuePair(sPara));
        request.setUrl(ALIPAY_GATEWAY_NEW + "_input_charset=" + AlipayConfig.input_charset);

        HttpResponse response = httpProtocolHandler.execute(request, strParaFileName, strFilePath);
        if (response == null) {
            return null;
        }

        String strResult = response.getStringResult();

        return strResult;
    }

    /**
     * @Desc MAP类型数组转换成NameValuePair类型
     * @Author zhangjin
     * @Date 2015年10月30日 下午3:25:33
     * @param properties MAP类型数组
     * @return NameValuePair类型数组
     */
    private static NameValuePair[] generatNameValuePair(Map<String, String> properties) {
        NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
        int i = 0;
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            nameValuePair[i++] = new NameValuePair(entry.getKey(), entry.getValue());
        }

        return nameValuePair;
    }

    /**
     * @Desc 用于防钓鱼，调用接口query_timestamp来获取时间戳的处理函数
     * @Author zhangjin
     * @Date 2015年10月30日 下午3:25:59
     * @return 时间戳字符串
     * @throws MalformedURLException 异常
     * @throws DocumentException 异常
     * @throws IOException 异常
     */
    public static String query_timestamp() throws MalformedURLException, DocumentException, IOException {

        // 构造访问query_timestamp接口的URL串
        String strUrl = ALIPAY_GATEWAY_NEW + "service=query_timestamp&partner=" + AlipayConfig.partner + "&_input_charset" + AlipayConfig.input_charset;
        StringBuffer result = new StringBuffer();

        SAXReader reader = new SAXReader();
        Document doc = reader.read(new URL(strUrl).openStream());

        List<Node> nodeList = doc.selectNodes("//alipay/*");

        for (Node node : nodeList) {
            // 截取部分不需要解析的信息
            if (node.getName().equals("is_success") && node.getText().equals("T")) {
                // 判断是否有成功标示
                @SuppressWarnings("unchecked")
                List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");
                for (Node node1 : nodeList1) {
                    result.append(node1.getText());
                }
            }
        }

        return result.toString();
    }

    /**
     *
     * sendRequest,调用支付宝接口. <br/>
     * Author: zhangjin <br/>
     * Create Date: 2016年5月24日 <br/>
     * ===============================================================<br/>
     * Modifier: zhangjin <br/>
     * Modify Date: 2016年5月24日 <br/>
     * Modify Description: <br/>
     * ===============================================================<br/>
     *
     * @param sParaTemp 请求参数
     * @param response 响应
     * @throws Exception 异常
     * @since JDK 1.7
     */
    public static void sendRequest(Map<String, String> sParaTemp, HttpServletResponse response) {
        response.setContentType("text/html; charset=utf-8");
        PrintWriter out;
        try {
            out = response.getWriter();
            String sHtmlText = buildRequest(sParaTemp, "get", "确认");
            out.print(sHtmlText);
            out.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();

        }

    }
}